package com.ws.framework.util;

import java.lang.reflect.Array;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.ws.framework.ex.DigestException;

public class ParamUtil {

    /**
     * 基本数据类型
     */
    @SuppressWarnings({"rawtypes", "serial"})
    private static final Set<Class> BASEDATATYPE = new HashSet<Class>() {
        {
            add(short.class);
            add(int.class);
            add(long.class);
            add(float.class);
            add(double.class);
            add(boolean.class);
            add(char.class);
            add(Short.class);
            add(Integer.class);
            add(Long.class);
            add(Float.class);
            add(Double.class);
            add(Boolean.class);
            add(Character.class);
            add(String.class);
        }
    };

    @SuppressWarnings("rawtypes")
    public static String getParamFromMap(Map<String, Object> map) {
        if (map == null) {
            throw new IllegalArgumentException("map is null!");
        }
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(map.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            public int compare(Map.Entry<String, Object> entry1, Map.Entry<String, Object> entry2) {
                return entry1.getKey().compareTo(entry2.getKey());
            }
        });
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, Object> entry : mappingList) {
            Object obj = entry.getValue();
            if (BASEDATATYPE.contains(obj.getClass())) { // String类型
                builder.append(entry.getKey()).append("=").append(obj).append("&");
            } else if (obj.getClass().isArray()) {
                int arrLength = Array.getLength(obj);
                if (arrLength > 0) {
                    for (int i = 0; i < arrLength; i++) {
                        builder.append(entry.getKey()).append("=").append(Array.get(obj, i)).append("&");
                    }
                }
            } else if (obj instanceof Collection) {
                Collection collection = (Collection) obj;
                if (collection.size() > 0) {
                    for (Object o : collection) {
                        builder.append(entry.getKey()).append("=").append(o).append("&");
                    }
                }
            } else {
                throw new DigestException("Can't parse complex Object:" + obj.getClass());
            }
        }
        builder.deleteCharAt(builder.lastIndexOf("&"));
        return builder.toString();
    }

    @SuppressWarnings("rawtypes")
    public static String getEncodedParamFromMap(Map<String, Object> map) {
        try {
			if (map == null) {
			    throw new IllegalArgumentException("map is null!");
			}
			Map<String, Object> encodedMap = new HashMap<String, Object>();
			for (Map.Entry<String, Object> entry : map.entrySet()) {
			    Object obj = entry.getValue();
			    if (obj instanceof String) {
			        encodedMap.put(entry.getKey(), URLEncoder.encode((String) obj, "UTF-8"));
			    } else if (obj.getClass().isArray()) {
			        int arrLength = Array.getLength(obj);
			        Object[] arr = new Object[arrLength];
			        for (int i = 0; i < arrLength; i++) {
			            if (Array.get(obj, i) instanceof String) {
			                arr[i] = URLEncoder.encode((String) Array.get(obj, i), "UTF-8");
			            } else {
			                arr[i] = Array.get(obj, i);
			            }
			        }
			        encodedMap.put(entry.getKey(), arr);
			    } else if (obj instanceof Collection) {
			        Collection collection = (Collection) obj;
			        int arrLength = collection.size();
			        Object[] arr = new Object[arrLength];
			        int i = 0;
			        for (Object o : collection) {
			            if (o instanceof String) {
			                arr[i] = URLEncoder.encode((String) o, "UTF-8");
			            } else {
			                arr[i] = o;
			            }
			            i++;
			        }
			        encodedMap.put(entry.getKey(), arr);
			    } else {
			        encodedMap.put(entry.getKey(), obj);
			    }
			}
			return getParamFromMap(encodedMap);
		} catch (Exception e) {
			throw new DigestException("Sort then encode param ocurr error. param map is " + map, e);
		} 
    }
}
